home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / comm_c_2.zip / COMM.C < prev    next >
Text File  |  1990-04-28  |  15KB  |  366 lines

  1.       #define DEBUG      /* comment me to eliminate main()
  2.  
  3. /*    From CompuServe's BPROGB Borland Int'l forum
  4.  *
  5.  *    #:  11879 S4/Turbo C
  6.  *        02-Jun-88  18:54:50
  7.  *    Sb: #11817-VT100
  8.  *    Fm: Jerry Joplin 70441,2627
  9.  *    To: Pete Gontier 72261,1754 (X)
  10.  *
  11.  *    Pete, here are the communication ISR's I've been using.   Hope these
  12.  *    don't overflow the message data base for BPROGB.  :-)
  13.  *    I think all is included to set up COM1/COM2 for receiver interrupts.
  14.  *
  15.  *    Also, these are straight ports from routines in MSKERMIT 2.30 and CKERMIT
  16.  *    for UNIX, which are public domain but copyrighted (c) by Columbia
  17.  *    University.
  18.  */
  19.  
  20. /*    Modification, to support other compiler(s):
  21.  *       Pete Gontier, July 20th, 1988
  22.  *    This code is no longer portable to the UNIX systems mentioned.
  23.  *    The function names were in accordance with the TT teletype conventions,
  24.  *    and I couldn't stand for it. So sue me.
  25.  */
  26.  
  27. /*    Modification, to support comm ports 3 & 4
  28.  *       Al Sharpe, June 7, 1989
  29.  *    Minor changes added to handle DTR on port close.
  30.  *
  31.  *    New function added :
  32.  *      flsh_dtr( )   -  drops DTR for 200 milliseconds
  33.  *
  34.  *    Old function modified :
  35.  *      comm_getc( unsigned seconds )   -  (1) gets a char from input buffer
  36.  *                                             with timeout
  37.  *                                         (2) if a key is pressed a Timeout
  38.  *                                             is returned
  39.  */
  40.  
  41. /*     Last modification by Al Sharpe, April 28, 1990.
  42.  *
  43.  *     - corrected comm_close() to drop RTS and DTR, not just DTR.
  44.  *     - correct flsh_dtr( ) to drop only DTR and leave RTS active.
  45.  *     - flsh_dtr( ) duration extented to 1/2 second.
  46.  *     - correct all bugs in function main( ) so test program will work.
  47.  *     - removed global CARRIER as it was redundant.
  48.  *     - conio.h added for cprintf( ) function.
  49.  */
  50.  
  51.  
  52. #include <dos.h>
  53. #include <bios.h>
  54. #include <conio.h>
  55.  
  56. #define TCICOMM    /* avoid extern declaration in... */
  57. #include "comm.h"  /* comm prototypes */
  58.  
  59. /** macros for absolute data ************************************************/
  60.  
  61. #define MDMDAT1 0x03F8            /* Address of modem port 1 data */
  62. #define MDMSTS1 0x03FD            /* Address of modem port 1 status  */
  63. #define MDMCOM1 0x03FB            /* Address of modem port 1 command */
  64. #define MDMDAT2 0x02F8            /* Address of modem port 2 data */
  65. #define MDMSTS2 0x02FD            /* Address of modem port 2 status */
  66. #define MDMCOM2 0x02FB            /* Address of modem port 2 command */
  67. #define MDMDAT3 0x03E8            /* Address of modem port 3 data */
  68. #define MDMSTS3 0x03ED            /* Address of modem port 3 status  */
  69. #define MDMCOM3 0x03EB            /* Address of modem port 3 command */
  70. #define MDMDAT4 0x02E8            /* Address of modem port 4 data */
  71. #define MDMSTS4 0x02ED            /* Address of modem port 4 status */
  72. #define MDMCOM4 0x02EB            /* Address of modem port 4 command */
  73. #define MDMINTV 0x000C            /* Com 1 & 3 interrupt vector */
  74. #define MDINTV2 0x000B            /* Com 2 & 4 interrupt vector */
  75. #define MDMINTO 0x0EF             /* Mask to enable IRQ3 for port 1 & 3 */
  76. #define MDINTO2 0x0F7             /* Mask to enable IRQ4 for port 2 & 4 */
  77. #define MDMINTC 0x010             /* Mask to Disable IRQ4 for port 1 & 3 */
  78. #define MDINTC2 0x008             /* Mask to Disable IRQ3 for port 2 & 4 */
  79. #define INTCONT 0x0021            /* 8259 interrupt controller ICW2-3 */
  80. #define INTCON1 0x0020            /* Address of 8259 ICW1 */
  81. #define CBS     2048              /* Communications port buffer size */
  82. #define XOFF    0x13              /* XON/XOFF */
  83. #define XON     0x11
  84. #define CARRIER_ON  0x80          /* Return value for carrier detect */
  85.  
  86.  
  87. /** globals not externally accessible ***************************************/
  88.  
  89. static int   MODEM_STAT;          /* 8250 modem status register */
  90. static int   dat8250;             /* 8250 data register */
  91. static int   stat8250;            /* 8250 line-status register */
  92. static int   com8250;             /* 8250 line-control register */
  93. static char  en8259;              /* 8259 IRQ enable mask */
  94. static char  dis8259;             /* 8259 IRQ disable mask */
  95. static unsigned int intv;         /* interrupt number to usurp */
  96.  
  97. static char  buffer[CBS];         /* Communications circular buffer */
  98. static char *inptr;               /* input address of circular buffer */
  99. static char *outptr;              /* output address of circular buffer */
  100. static int   c_in_buf = 0;        /* count of characters received */
  101. static int   xoffpt;              /* amount of buffer that forces XOFF */
  102. static int   xonpt;               /* amount of buffer that unXOFFs */
  103.  
  104.  
  105. static void interrupt ( far *oldvec ) ( );
  106.                                   /* vector of previous comm interrupt */
  107.  
  108. int xonxoff = 0;                          /* auto xon/xoff support flag */
  109. int xofsnt  = 0;                          /* XOFF transmitted flag */
  110. int xofrcv  = 0;                          /* XOFF received flag */
  111.  
  112. void interrupt serint ( void ) {          /* ISR to receive character */
  113.    *inptr++ = inportb ( dat8250 );        /* Store character in buffer */
  114.    c_in_buf++;                            /* and increment count */
  115.    if ( xonxoff ) {                       /* if xon/xoff auto-support is on */
  116.       if ( c_in_buf > xoffpt && ! xofsnt ) {  /* then if buf nearly full */
  117.          comm_putc ( XOFF );              /* send an XOFF */
  118.          xofsnt = 1;                      /* and say so */
  119.       }
  120.    }
  121.    disable ( );                           /* ints off for ptr change */
  122.    if ( inptr == &buffer[CBS] )           /* Set buffer input pointer */
  123.       inptr = buffer;
  124.    enable ( );
  125.    outportb ( 0x20, 0x20 );               /* Generic EOI to 8259 */
  126. }
  127.  
  128.  
  129. void comm_close ( void ) {             /* restore previous settings of 8259 */
  130.  
  131.     outportb ( com8250 + 1, 0x08 );      /* Drop OUT2 */
  132.     outportb ( com8250 + 1, 0x00 );      /* Drop DTR and RTS /*
  133.     outportb ( INTCONT, dis8259 | inportb ( INTCONT ) );
  134.        /* Disable com interrupt at 8259 */
  135.      setvect ( intv, oldvec );      /* Reset original interrupt vector */
  136. }
  137.  
  138. void dobaud ( unsigned baudrate ) {     /* parses baud integer to mask,
  139.                                          * re-inits port accordingly */
  140.    unsigned char portval;
  141.    unsigned char blo, bhi;
  142.    switch  ( baudrate ) {          /* Baud rate LSB's and MSB's */
  143.        case 50:     bhi = 0x9;  blo = 0x00;  break;
  144.        case 75:     bhi = 0x6;  blo = 0x00;  break;
  145.        case 110:    bhi = 0x4;  blo = 0x17;  break;
  146.        case 150:    bhi = 0x3;  blo = 0x00;  break;
  147.        case 300:    bhi = 0x1;  blo = 0x80;  break;
  148.        case 600:    bhi = 0x0;  blo = 0xC0;  break;
  149.        case 1200:   bhi = 0x0;  blo = 0x60;  break;
  150.        case 1800:   bhi = 0x0;  blo = 0x40;  break;
  151.        case 2000:   bhi = 0x0;  blo = 0x3A;  break;
  152.        case 2400:   bhi = 0x0;  blo = 0x30;  break;
  153.        case 4800:   bhi = 0x0;  blo = 0x18;  break;
  154.        case 9600:   bhi = 0x0;  blo = 0x0C;  break;
  155.        case 19200:  bhi = 0x0;  blo = 0x06;  break;
  156.        default:
  157.            return;
  158.    }
  159.    portval = inportb ( com8250 );         /* read Line-Control Reg val */
  160.    outportb ( com8250, portval | 0x80 );  /* set high bit for baud init */
  161.    outportb ( dat8250, blo );             /* Send LSB for baud rate */
  162.    outportb ( dat8250 + 1, bhi );         /* Send MSB for baud rate */
  163.    outportb ( com8250, portval );         /* Reset initial value at LCR */
  164. }
  165.  
  166.  
  167. /* installs comm interrupts */
  168.  
  169. int comm_open ( int portid, unsigned speed )
  170. {
  171.    int be = biosequip ( );      /* to get # installed serial ports */
  172.    be <<= 4;                    /* shift-wrap high bits off */
  173.    be >>= 13;                   /* shift down to low bits */
  174.    if ( be >= portid || portid >= 3) {
  175.       if ( portid == 1 ) {
  176.           dat8250  = MDMDAT1;
  177.           stat8250 = MDMSTS1;
  178.           com8250  = MDMCOM1;
  179.           dis8259  = MDMINTC;
  180.           en8259   = MDMINTO;
  181.           intv = MDMINTV;
  182.           }
  183.       else if ( portid == 2 ) {
  184.           dat8250  = MDMDAT2;
  185.           stat8250 = MDMSTS2;
  186.           com8250  = MDMCOM2;
  187.           dis8259  = MDINTC2;
  188.           en8259   = MDINTO2;
  189.           intv = MDINTV2;
  190.           }
  191.       else if ( portid == 3 ) {        /* Ports 3 & 4 cannot be checked */
  192.       dat8250  = MDMDAT3;           /* with biosquip( ) */
  193.           stat8250 = MDMSTS3;
  194.           com8250  = MDMCOM3;
  195.           dis8259  = MDMINTC;
  196.           en8259   = MDMINTO;
  197.           intv = MDMINTV;
  198.           }
  199.       else if ( portid == 4 ) {
  200.           dat8250  = MDMDAT4;
  201.           stat8250 = MDMSTS4;
  202.           com8250  = MDMCOM4;
  203.           dis8259  = MDINTC2;
  204.           en8259   = MDINTO2;
  205.           intv = MDINTV2;
  206.           }
  207.       else
  208.          return ( 0 );
  209.  
  210.       MODEM_STAT = dat8250 + 6;           /* Define Modem Status Register */
  211.  
  212.       dobaud ( speed );                   /* set baud */
  213.       inptr = outptr = buffer;            /* set circular buffer values */
  214.       c_in_buf = 0;
  215.       oldvec = getvect ( intv );          /* Save old int vector */
  216.       setvect  ( intv, serint );          /* Set up SERINT as com ISR */
  217.       outportb ( com8250,     0x3 );      /* 8 bits no parity */
  218.       outportb ( com8250 + 1, 0xb );      /* Assert OUT2, RTS, and DTR */
  219.       inportb  ( dat8250 );
  220.       outportb ( dat8250 + 1, 0x1 );      /* Receiver-Data-Ready int */
  221.       outportb ( INTCONT, en8259 & inportb ( INTCONT ) );
  222.                                           /* Enable 8259 interrupts */
  223.       xoffpt = CBS - 128;                 /* chars in buff to send XOFF */
  224.       xonpt  = CBS - xoffpt;              /* chars in buff to send XON */
  225.      }
  226.    else
  227.       be = 0;
  228.    return ( be );
  229. }
  230.  
  231.  
  232. int comm_avail ( )       /* returns # characters available in buffer */
  233. {
  234.     return ( c_in_buf );
  235. }
  236.  
  237.  
  238. void comm_putc ( unsigned char c )      /* sends char out port */
  239. {
  240.     while ( ( inportb ( stat8250 ) & 0x20 ) == 0 );
  241.                     /* Wait til transmitter is ready */
  242.     outportb ( dat8250, c );            /* then send it */
  243. }
  244.  
  245.  
  246. int comm_getc ( unsigned seconds )         /* gets char from buffer */
  247. {
  248.     int c;
  249.     long get_tm, end_tm;
  250.  
  251.     register char * ptr;
  252.     if ( c_in_buf < xonpt && xofsnt ) {   /* Check if we need to send */
  253.        xofsnt = 0;                        /* an XON to the host after */
  254.        comm_putc ( XON );                 /* we had to send an XOFF */
  255.        }
  256.  
  257.     get_tm = biostime(0,0);               /* If character not ready */
  258.     end_tm = get_tm + (18 * seconds);     /* then wait til one is   */
  259.                                           /* or return TIMEOUT */
  260.     do {
  261.         if(kbhit()) {                     /* If key pressed, Timeout */
  262.             getch();                      /* is returned */
  263.             comm_putc('\20');             /* send 'space' to modem to */
  264.         return(USR_BRK);                  /* cancel off-hook */
  265.             }
  266.         get_tm = biostime(0,0);           /* check Timeout counter */
  267.         }
  268.     while(get_tm <= end_tm && c_in_buf == 0) ;
  269.  
  270.     if(get_tm >= end_tm) return(TIMEOUT);  /* port timed out */
  271.  
  272.     ptr = outptr;
  273.     c = *ptr++;                     /* Get next character in circular buff */
  274.     if ( ptr == &buffer[CBS] )      /* Check for end of circular buffer */
  275.         ptr = buffer;               /* start from bottom of buff */
  276.     disable ( );                    /* no interrupts during pointer manips */
  277.     outptr = ptr;                   /* set character output pointer */
  278.     c_in_buf--;                     /* and decrement the character count */
  279.     enable ( );                     /* then allow interrupts to continue */
  280.     return ( c );                   /* Return the character */
  281. }
  282.  
  283. void comm_flush ( )                 /* flushes all chars out of buffer */
  284. {
  285.     if ( xofsnt ) {                 /* Check if XON needs to be sent */
  286.        xofsnt = 0;
  287.        comm_putc ( XON );
  288.     }
  289.     disable ( );                    /* no interrupts during pointer manips */
  290.     inptr = outptr = buffer;        /* reset buffer pointers */
  291.     c_in_buf = 0;                   /* and indicate no chars received */
  292.     enable ( );
  293. }
  294.  
  295. void flsh_dtr ( )                   /* Drop DTR for 1/2 second */
  296. {
  297.     outportb( com8250 + 1, 0xa);    /* Un-set DTR (set RTS, OUT2) */
  298.     delay(500);                     /* Wait for 1/2 second */
  299.     outportb( com8250 + 1, 0xb);    /* Set DTR, RTS, OUT2 */
  300.  
  301. }
  302.  
  303.  
  304. int carrier( )          /* TEST FOR CARRIER DETECT */
  305. {
  306.  
  307.     delay(200);                     /* Short pause */
  308.     if((inportb( MODEM_STAT ) & CARRIER_ON ) == CARRIER_ON)
  309.         return(1);                  /* Check MSR for DCD */
  310.     return(0);
  311.  
  312. }
  313.  
  314. /****************************************************************************/
  315.  
  316. #ifdef DEBUG
  317.  
  318. #include <string.h>
  319.  
  320. main( int argc, char *argv[] )
  321. {
  322.    char result = 0;
  323.    int port = 1, speed = 1200;      /* Default speed & port */
  324.    char c=0;
  325.  
  326.    if( argc >= 2 ) port = *argv[1] - 48;
  327.    if( argc == 3 ) speed = atoi( argv[2] );
  328.  
  329.    cprintf ( "\r\n"
  330.        "Serial port %d open at %d baud\r\n"
  331.        "test terminal for C comm isr's in power 1.X, turbo 1.X\r\n"
  332.        "hit \"ESC\" to exit\r\n\n", port, speed );
  333.    if ( comm_open ( port, speed ) ) {
  334.       while ( result != 27 && c != TIMEOUT) {
  335.          if ( kbhit() ) {               /* Check for keyboard press */
  336.         result = getch();
  337.         if( result != 27 )  comm_putc ( result );   /* If ! Escape */
  338.         }                                           /* Output the char */
  339.      if(comm_avail()) {                             /* Is a char waiting? */
  340.          c = comm_getc(3);
  341.          switch ( c ) {
  342.              case '\t' :                            /* convert tabs */
  343.                 for ( c = 0; c < 8; c++ )
  344.                 putch ( ' ' );
  345.                 break;
  346.              case TIMEOUT :                         /* check for timeout */
  347.                 cprintf("\r\nPort Timed Out\r\n");  /* error */
  348.                 break;
  349.              default :
  350.                 cprintf ("%c", c );                 /* put char to screen */
  351.                 break;
  352.              }
  353.           }
  354.       }
  355.  
  356.       cprintf("\nClosing Port %d\n",port);
  357.       comm_close();
  358.    }
  359.    else
  360.       cprintf ( "\r\nUnable to find port %d\r\n", port );
  361.    return ( 0 );
  362. }
  363.  
  364. #endif
  365.  
  366.